using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using Barrage.Global;
using System.IO;
using System.Globalization;
using SlimDX;

namespace Spacedash.Logic
{
    /// <summary>
    /// Profile stores information about a player's data: Name and Ship performance parameters.
    /// It also loads and stores this information on XML files.
    /// </summary>
    public class Profile
    {
        static bool pathAdded = false;
        static void AddPath()
        {
            if (!Store.PathConfig.Contains(PROFILE_PATH))
            {
                Store.PathConfig.Add(PROFILE_PATH, PROFILE_DEFAULT_PATH);
                pathAdded = true;
            }
        }
        /// <summary>
        /// Path Identifier of the profile path
        /// </summary>
        public const string PROFILE_PATH = "ProfilePath";
        private const string PROFILE_DEFAULT_PATH = "Profiles/";
        private const string XML_PROFILE_ROOT = "Profile";
        private const string XML_NAME_ATTRIBUTE = "name";
        private const string XML_SPEED_ATTRIBUTE = "speed";
        private const string XML_SHIPMODEL_ATTRIBUTE = "shipModel";
        private const string XML_PURSUIT_ATTRIBUTE = "pursuit";
        private const string XML_HANDLING_ATTRIBUTE = "handling";

        private const float DEFAULT_SPEED = 0.5f;
        private const float DEFAULT_PURSUIT = 0.5f;
        private const float DEFAULT_HANDLING = 0.5f;

        private const float TOTAL_SUM = 1.5f;

        private string name;
        /// <summary>
        /// Name of the profile's nick
        /// </summary>
        public string Name { get { return name; } set { name = value; } }

        private ShipModel shipModelInstance;
        /// <summary>
        /// Returns an instance of the Ship Model that the player has selected
        /// </summary>
        public ShipModel ShipModelInstance { get { if (shipModelInstance == null) shipModelInstance = Spacedash.Logic.ShipModel.Load(shipModel); return shipModelInstance; } }

        private string shipModel;
        /// <summary>
        /// Name of the Ship Model that the player will use on the races.
        /// </summary>
        public string ShipModel { get { return shipModel; } set { shipModel = value; shipModelInstance = null; } }

        private float pursuit;

        /// <summary>
        /// Pursuit Ship parameter
        /// </summary>
        public float Pursuit
        {
            get { return pursuit; }
            set
            {
                pursuit = Math.Min(1,Math.Max(0,value));
                Redistribute(ref speed, ref handling);
            }
        }

        float TotalSum { get { return pursuit + handling + speed; } }

        void Redistribute(ref float value,ref float value2)
        {

            float tSum = TotalSum;
            value = Math.Min(1, Math.Max(0, value + (TOTAL_SUM - tSum) / 2f));
            value2 = Math.Min(1, Math.Max(0, value2 + (TOTAL_SUM - tSum) / 2f));
        }

        void Redistribute()
        {
            float tSum = TotalSum;
            speed = Math.Min(1,Math.Max(0,speed+ (TOTAL_SUM - tSum) / 3f));
            handling = Math.Min(1, Math.Max(0, handling + (TOTAL_SUM - tSum) / 3f));
            pursuit = Math.Min(1, Math.Max(0, pursuit + (TOTAL_SUM - tSum) / 3f));
            
            
        }

        private float handling;

        /// <summary>
        /// Handling Ship parameter
        /// </summary>
        public float Handling
        {
            get { return handling; }
            set
            {
                handling = Math.Min(1, Math.Max(0, value));
                Redistribute(ref speed,ref pursuit);
            }
        }
	
        private float speed;

        /// <summary>
        /// Speed ship parameter
        /// </summary>
        public float Speed
        {
            get { return speed; }
            set
            {
                speed = Math.Min(1, Math.Max(0, value));
                Redistribute(ref pursuit,ref handling);
            }
        }

        /// <summary>
        /// Creates a profile with the name specified and default values
        /// </summary>
        /// <param name="name">Profile name</param>
        public Profile(string name):this(name,"",DEFAULT_SPEED,DEFAULT_PURSUIT,DEFAULT_HANDLING){

        }
        /// <summary>
        /// Creates a profile with the specified values
        /// </summary>
        /// <param name="name">Profile name</param>
        /// <param name="shipModel">Ship model name</param>
        /// <param name="speed">Speed value</param>
        /// <param name="pursuit">Pursuit value</param>
        /// <param name="handling">Handling value</param>
        public Profile(string name, string shipModel, float speed, float pursuit, float handling)
        {
            this.name = name;
            this.shipModel = shipModel;
            this.speed = speed;
            this.pursuit = pursuit;
            this.handling = handling;

            Redistribute();
        }
	
        /// <summary>
        /// Loads the specified profile from disk
        /// </summary>
        /// <param name="name">Profile name</param>
        /// <returns>Loaded profile or null if it couldn't be done</returns>
        public static Profile Load(string name)
        {
            if (!pathAdded) AddPath();

            XmlDocument xd = new XmlDocument();
            xd.Load(Store.PathConfig[PROFILE_PATH]+name+".xml");
            foreach (XmlNode xn in xd.ChildNodes)
            {
                if (xn.Name.Equals(XML_PROFILE_ROOT))
                {
                    return new Profile(XmlHelper.GetXMLAttribute(xn, XML_NAME_ATTRIBUTE), XmlHelper.GetXMLAttribute(xn,XML_SHIPMODEL_ATTRIBUTE),XmlHelper.ParseXMLFloatAttribute(xn, XML_SPEED_ATTRIBUTE, DEFAULT_SPEED), XmlHelper.ParseXMLFloatAttribute(xn, XML_PURSUIT_ATTRIBUTE, DEFAULT_PURSUIT), XmlHelper.ParseXMLFloatAttribute(xn, XML_HANDLING_ATTRIBUTE, DEFAULT_HANDLING));
                }
            }
            return null;
        }

        /// <summary>
        /// Returns a list of available profiles in the profile directory
        /// </summary>
        /// <returns>List of profile names</returns>
        public static List<string> GetAvailableProfiles()
        {
            if (!pathAdded) AddPath();
            
            List<string> names = new List<string>();
            DirectoryInfo di = new DirectoryInfo(Store.PathConfig[PROFILE_PATH] );
            if (!di.Exists) return names;
            FileInfo[] files = di.GetFiles("*.xml", SearchOption.TopDirectoryOnly);
            foreach (FileInfo fi in files)
            {
                string name = fi.Name;
                name = name.Substring(0,name.Length-4);
                names.Add(name);
            }
            return names;
        }

        /// <summary>
        /// Saves the current profile to disk
        /// </summary>
        public void Save()
        {
            if (!pathAdded) AddPath();

            XmlDocument xd = new XmlDocument();
            XmlElement x = xd.CreateElement(XML_PROFILE_ROOT);
            x.SetAttribute(XML_NAME_ATTRIBUTE,name);
            x.SetAttribute(XML_SHIPMODEL_ATTRIBUTE, shipModel);
            x.SetAttribute(XML_SPEED_ATTRIBUTE, speed.ToString(NumberFormatInfo.InvariantInfo));
            x.SetAttribute(XML_PURSUIT_ATTRIBUTE,pursuit.ToString(NumberFormatInfo.InvariantInfo));
            x.SetAttribute(XML_HANDLING_ATTRIBUTE,handling.ToString(NumberFormatInfo.InvariantInfo));
            xd.AppendChild(x);
            xd.Save(Store.PathConfig[PROFILE_PATH]+name+".xml");
        }

        /// <summary>
        /// Returns the color associated to the profile ship handling parameters
        /// </summary>
        public Color3 Color
        {
            get
            {
                return new Color3(Speed, Handling, Pursuit);
            }
        }
    }
}
